package com.wang.tool.dagre;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wang.tool.common.ErrorInfo;
import com.wang.tool.common.SimpleException;
import com.wang.tool.util.SimpleLogUtil;
import com.wang.tool.dagre.node.DagreNode;
import com.wang.tool.monitor.InvokeTemplate;
import com.wang.tool.monitor.LinkLogUtil;
import com.wang.tool.monitor.core.MonitorInfo;
import com.wang.tool.monitor.template.MonitorInvoker;
import com.wang.tool.util.*;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * 简易图流程引擎实现
 *
 * @Author shaopeng
 * @Date 2021/6/19
 * @see DagreEngine#getName
 * @see DagreEngine#addNode
 * @see DagreEngine#run
 * @see DagreEngine#drawDagre
 * @see DagreNode
 */
public class DagreEngine<T> {

    /**
     * 节点触发
     */
    public static final String TAG_FIRE_DAGRE_NODE = "FireDagreNode";

    /**
     * 节点取消
     */
    public static final String TAG_DAGRE_CANCEL_WORKER = "DagreCancelWorker";

    /**
     * 尝试取消节点
     */
    public static final String TAG_TRY_CANCEL_DAGRE_NODE = "TryCancelDagreNode";

    /**
     * 尝试取消上游节点
     */
    public static final String TAG_TRY_CANCEL_UP_DAGRE_NODE = "TryCancelUpDagreNode";

    /**
     * 节点取消执行
     */
    public static final String TAG_CANCEL_DAGRE_NODE = "CancelDagreNode";

    /**
     * 节点结果快照记录失败
     */
    public static final String TAG_NODE_RESULT_SNAPSHOT_ERROR = "NodeResultSnapshotError";
    /**
     * 流程已结束
     */
    public static final String TAG_DAGRE_ALREADY_DONE = "DagreAlreadyDone";


    /**
     * 引擎名称
     * 非空
     */
    private String name = "UNKNOWN";

    /**
     * 主线程池 非空
     * 异步执行节点用
     */
    private ExecutorService mainExecutor;

    /**
     * 节点选择器 非空
     * 招工
     * 选择需要执行的节点列表
     * tips:后续会对节点进行依赖必要性补全
     */
    private NodeSelector<T> nodeSelector;

    /**
     * 运行
     * 运行结束有四种情况
     * 1.任一节点报错
     * 2.执行超时
     * 3.某一节点返回的结果是DagreResult类型对象
     * 4.所有节点执行完毕
     *
     * @param param   非空
     * @param timeout 超时时间 可为空
     * @return 概况 非空
     */
    public DagreResult run(T param, Integer timeout) {
        return InvokeTemplate.monitor("Dagre", name, "run", new MonitorInvoker<DagreResult>(param, timeout) {
            private DagreContext<T> context;

            @Override
            public void weaveOnBefore(MonitorInfo<DagreResult> monitorInfo) {
                monitorInfo.addDigest("timeout", timeout);
                if (monitorInfo.isDebug()) {
                    monitorInfo.addDetailParam(param);
                }
            }

            @Override
            public DagreResult internalCall() throws Throwable {
                if (param == null) {
                    return DagreResult.buildError(new SimpleException(SimpleException.PARAM_INVALID, "context/param can not be null"));
                }
                if (mainExecutor == null) {
                    return DagreResult.buildError(new SimpleException(SimpleException.CONFIG_INVALID, "mainExecutor can not be null"));
                }
                if (name == null) {
                    return DagreResult.buildError(new SimpleException(SimpleException.CONFIG_INVALID, "dagreName can not be null"));
                }
                if (nodeSelector == null) {
                    return DagreResult.buildError(new SimpleException(SimpleException.CONFIG_INVALID, "nodeSelector can not be null"));
                }

                //准备
                context = prepare(param, timeout);
                if (context == null) {
                    DagreResult result = DagreResult.buildSuccess(null);
                    result.setStatus(DagreResult.StatusEnum.ZERO_NODE);
                    return result;
                }
                //执行并开枝散叶
                return executeNodes(context);
            }

            @Override
            public DagreResult handleError(Throwable e, ErrorInfo error) {
                DagreResult result = DagreResult.buildError(error);
                //标记结束
                if (context != null) {
                    context.markDagreDone(null, result);
                }
                return result;
            }

            @Override
            public void weaveOnAfter(MonitorInfo<DagreResult> monitorInfo) {
                DagreResult result = monitorInfo.getResult();
                //状态
                monitorInfo.setStatus(result.isSuccess() ? result.getData() == null ? MonitorInfo.NULL : MonitorInfo.OK : result.getError().getErrorCode() == null ? "UNKNOWN_ERROR" : result.getError().getErrorCode());
                //耗时
                result.setCost(monitorInfo.getCost());
                monitorInfo.addDigest("status", result.getStatus());
                if (context == null) {
                    return;
                }

                //执行状态转移
                result.setNodeStates(context.getNodeStates());
            }
        });
    }

    /**
     * 画链路
     *
     * @param result 执行result
     * @return
     */
    public JSONObject drawDagre(DagreResult result) {
        if (result == null) {
            return null;
        }
        JSONObject detail = new JSONObject();
        detail.put("cost", result.getCost());
        detail.put("error", result.getError());
        Map<String, Object> val = new HashMap<>(2);
        val.put("data", result.getData());
        val.put("ext", result.getExt());
        detail.put("result", val);
        detail.put("status", result.getStatus());
        detail.put("finishNodeId", result.getFinishNodeId());
        Map<String, NodeState> nodeStates = result.getNodeStates();
        if (nodeStates == null) {
            return detail;
        }
        detail.put("nodeStates", nodeStates.values().stream().map(state -> {
            String id = state.getId();
            NodeWrapper<T> wrapper = getNodeWrapper(id);
            if (wrapper == null) {
                throw new SimpleException(SimpleException.PARAM_INVALID, "id:{0} not exist in {1}", id, name);
            }
            DagreNode<T> node = wrapper.getNode();
            JSONObject obj = new JSONObject();
            obj.put("id", id);
            obj.put("typeName", node.getClass().getSimpleName());
            obj.put("sync", node.isSync());
            obj.put("depends", wrapper.getMeDepends());
            obj.put("begin", state.getBegin());
            obj.put("end", state.getEnd());
            obj.put("slow", state.getSlow());
            obj.put("ignore", state.isIgnore());
            if (CommonUtil.isNotBlank(state.getResultSnapshot())) {
                //仅当debug场景有值
                try {
                    //尝试当做对象
                    obj.put("result", JSON.parseObject(state.getResultSnapshot()));
                } catch (Throwable ignore) {
                    try {
                        //在尝试当做数组
                        obj.put("result", JSON.parseArray(state.getResultSnapshot()));
                    } catch (Throwable ignore2) {
                        //原对象
                        obj.put("result", state.getResultSnapshot());
                    }
                }
            }
            obj.put("error", state.getError());
            obj.put("status", state.isCancel() ? "CANCEL" : state.getBegin() == -1 ? "WAITING" : state.getEnd() == -1 ? "TIMEOUT" : state.getError() == null ? "SUCCESS" : state.getError().getErrorCode() == null ? "UNKNOWN_ERROR" : state.getError().getErrorCode());
            return obj;
        }).collect(Collectors.toList()));
        return detail;
    }


    /**
     * 添加节点
     *
     * @param nodes 节点
     * @return
     * @throws SimpleException 验证不通过抛出异常
     */
    public synchronized DagreEngine<T> addNode(DagreNode<T>... nodes) {
        if (freeze) {
            throw new SimpleException(SimpleException.UN_SUPPORT, "dagre:{0} is freeze unSupport addNode", name);
        }
        if (nodes == null) {
            return this;
        }
        for (DagreNode<T> node : nodes) {
            //注册前节点基础验证
            String id = node.getId();
            if (CommonUtil.isBlank(id)) {
                throw new SimpleException(SimpleException.CONFIG_INVALID, "node id is empty filter , node:{0}", node);
            }

            NodeWrapper<T> oldNode = getNodeWrapper(id);
            if (oldNode != null) {
                //依赖没变直接变更实现
                if (oldNode.getNode().getDependIds().equals(node.getDependIds())) {
                    SimpleLogUtil.info("[dagreChangeNode] name:{0}, id:{1}", name, node.getId());
                    oldNode.setNode(node);
                    return this;
                }
                //先解除注册
                removeNode(id);
            }
            nodeLibrary.put(node.getId(), new NodeWrapper<>(node));
            SimpleLogUtil.info("[dagreAddNode] name:{0}, id:{1}", name, node.getId());
        }
        //更新allIds
        allIds = Collections.unmodifiableSet(nodeLibrary.keySet());
        return this;
    }


    /**
     * 删除节点
     *
     * @param ids
     * @return
     * @throws SimpleException 验证不通过抛出异常
     */
    public synchronized DagreEngine<T> removeNode(String... ids) {
        if (freeze) {
            throw new SimpleException(SimpleException.UN_SUPPORT, "dagre:{0} is freeze unSupport removeNode", name);
        }
        if (ids == null) {
            return this;
        }
        for (String id : ids) {
            if (!hasNode(id)) {
                continue;
            }
            nodeLibrary.remove(id);
            SimpleLogUtil.info("[dagreRemoveNode] name:{0}, id:{1}", name, id);
        }
        //更新allIds
        allIds = Collections.unmodifiableSet(nodeLibrary.keySet());
        return this;
    }

    /**
     * 清理所有节点
     *
     * @return
     */
    public synchronized DagreEngine<T> clearNode() {
        if (freeze) {
            throw new SimpleException(SimpleException.UN_SUPPORT, "dagre:{0} is freeze unSupport clearNode", name);
        }
        nodeLibrary.clear();
        allIds = Collections.unmodifiableSet(nodeLibrary.keySet());
        SimpleLogUtil.info("[dagreClearNode] name:{0}", name);
        return this;
    }


    /**
     * 是否存在
     *
     * @param id
     * @return
     */
    public boolean hasNode(String id) {
        return id != null && nodeLibrary.containsKey(id);
    }

    /**
     * 根据id获取节点
     *
     * @param id
     * @return
     */
    public DagreNode<T> getNode(String id) {
        if (id == null) {
            return null;
        }
        NodeWrapper<T> nodeWrapper = getNodeWrapper(id);
        return nodeWrapper == null ? null : nodeWrapper.getNode();
    }

    /**
     * 提取所有nodeIds
     *
     * @return
     */
    public Set<String> getAllIds() {
        return allIds;
    }


    /**
     * 尝试冻结数据
     */
    public void tryFreeze() {
        if (freeze) {
            return;
        }
        synchronized (this) {
            if (freeze) {
                return;
            }
            freeze();
        }
    }

    public ExecutorService getMainExecutor() {
        return mainExecutor;
    }

    public void setMainExecutor(ExecutorService mainExecutor) {
        this.mainExecutor = mainExecutor;
    }


    /**
     * 名字
     */
    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }

    public NodeSelector<T> getNodeSelector() {
        return nodeSelector;
    }

    public void setNodeSelector(NodeSelector<T> nodeSelector) {
        this.nodeSelector = nodeSelector;
    }

    /*-------------------------分割线-------------------------*/


    /**
     * 准备
     *
     * @param param   非空
     * @param timeout 超时时间
     */
    protected DagreContext<T> prepare(T param, Integer timeout) {
        DagreEngine<T> dagre = this;
        return InvokeTemplate.monitor("Dagre", name, "prepare", new MonitorInvoker<DagreContext<T>>() {
            @Override
            public DagreContext<T> internalCall() {
                //初始化引擎依赖
                tryFreeze();
                Set<String> runIds = nodeSelector.selector(dagre, param, timeout);
                if (runIds == null) {
                    return null;
                }
                //自动填充上层节点
                completionNecessaryNode(runIds);
                //context准备
                return new DagreContext<>(name, param, timeout, nodeLibrary, runIds);
            }

            @Override
            public void weaveOnAfter(MonitorInfo<DagreContext<T>> monitorInfo) {
                DagreContext<T> result = monitorInfo.getResult();
                if (monitorInfo.isDebug() && result != null) {
                    //原型图
                    monitorInfo.addDetailResult(result.getRunIds());
                    monitorInfo.addShortDetailOnDebug(MonitorInfo.RESULT, result.getRunIds());
                }
            }
        });
    }

    /**
     * 补全必要的节点
     *
     * @param runIds
     */
    private void completionNecessaryNode(Set<String> runIds) {
        //所有节点都在了,不需要补全,这里使用相等更快,
        if (getAllIds() == runIds) {
            return;
        }
        //同个数
        if (getAllIds().size() == runIds.size()) {
            //验证节点是否存在即可
            for (String id : runIds) {
                if (!hasNode(id)) {
                    throw new SimpleException(SimpleException.PARAM_INVALID, "id:{0} not exist in {1}", id, name);
                }
            }
            return;
        }
        //等待验证的节点
        Set<String> stayIds = new HashSet<>(runIds);
        //递归添加依赖节点
        while (stayIds.size() > 0) {
            //需要增加的节点
            Set<String> addIds = new HashSet<>();
            for (String stayId : stayIds) {
                NodeWrapper<T> nodeWrapper = getNodeWrapper(stayId);
                if (nodeWrapper == null) {
                    throw new SimpleException(SimpleException.PARAM_INVALID, "id:{0} not exist in {1}", stayId, name);
                }
                Set<String> meDepend = nodeWrapper.getMeDepends();
                if (meDepend == null) {
                    continue;
                }
                for (String depend : meDepend) {
                    if (runIds.contains(depend)) {
                        continue;
                    }
                    addIds.add(depend);
                }
            }
            runIds.addAll(addIds);
            stayIds = addIds;
        }
    }


    /**
     * 执行节点
     * 结束有四种情况
     * 1.任一节点报错
     * 2.执行超时
     * 3.某一节点返回的结果是DagreResult类型对象
     * 4.所有节点执行完毕
     *
     * @param context 非空
     * @return 非空
     */
    private DagreResult executeNodes(DagreContext<T> context) throws Throwable {
        Set<String> runIds = context.getRunIds();
        //筛选起始节点
        List<NodeWrapper<T>> starts = getRoots().stream()
                .filter(nodeWrapper -> runIds.contains(nodeWrapper.fetchNodeId()))
                .collect(Collectors.toList());
        if (starts.isEmpty()) {
            //理论不存在
            throw new SimpleException(SimpleException.UN_EXPECT, "未发现执行根节点");
        }
        LinkLogUtil.newTagLog(TAG_FIRE_DAGRE_NODE)
                .v1(name)
                .v2("_root->" + CommonUtil.join(starts, ","))
                .log();
        //执行
        fireNodes(context, starts);
        //主线程等待结束
        return context.waitGetResult();
    }


    /**
     * 触发节点并开枝散叶
     *
     * @param context
     * @param nodeWrappers
     */
    private void fireNodes(DagreContext<T> context, Collection<NodeWrapper<T>> nodeWrappers) throws Throwable {
        for (NodeWrapper<T> nodeWrapper : nodeWrappers) {
            DagreNode<T> node = nodeWrapper.getNode();
            //标记为已取消
            if (context.isCancel(node.getId())) {
                LinkLogUtil.newTagLog(TAG_CANCEL_DAGRE_NODE)
                        .v1(name)
                        .v2(node.getId())
                        .log();
                //通知后续
                reportNodeDone(context, nodeWrapper, null);
                continue;
            }

            //记录此值可观察preCheck的耗时/调度耗时
            int begin = context.calRunTime();

            //同步预检验
            Object checkResult;
            try {
                checkResult = node.preCheck(context);
            } catch (Throwable e) {
                context.markDagreDone(node.getId(), DagreResult.buildError(e));
                //报错直接返回结果
                return;
            }

            //空转
            if (checkResult != null) {
                idlingNodeAndReport(begin, context, nodeWrapper, checkResult == DagreNode.NULL_VAL ? null : checkResult);
                continue;
            }

            //同步节点使用当前线程调用
            //实际上如果所有节点都是同步则可能会导致超时时间无效,这里忽略这种,应该不会有人这么玩
            if (node.isSync()) {
                //同步节点
                if (context.isDone()) {
                    //直接返回
                    return;
                }
                try {
                    Object nodeResult = syncExecuteNode(begin, context, node);
                    //通知后续
                    reportNodeDone(context, nodeWrapper, nodeResult);
                } catch (Throwable e) {
                    context.markDagreDone(node.getId(), DagreResult.buildError(e));
                    //报错直接返回结果
                    return;
                }
                continue;
            }

            //异步
            //执行并记录future
            context.addWorkFuture(node.getId(), mainExecutor.submit(() -> {
                if (context.isDone()) {
                    //直接返回
                    return;
                }
                try {
                    Object nodeResult = syncExecuteNode(begin, context, node);
                    //通知后续
                    reportNodeDone(context, nodeWrapper, nodeResult);
                } catch (Throwable e) {
                    context.markDagreDone(node.getId(), DagreResult.buildError(e));
                }
            }));
        }
    }

    /**
     * 空转节点&触发下游
     *
     * @param begin
     * @param context
     * @param nodeWrapper
     * @param result
     */
    protected void idlingNodeAndReport(int begin, DagreContext<T> context, NodeWrapper<T> nodeWrapper, Object result) throws Throwable {
        DagreNode<T> node = nodeWrapper.getNode();
        String id = node.getId();
        NodeState nodeState = context.getNodeState(id);
        InvokeTemplate.monitor("Dagre", name, "execute_" + id, new MonitorInvoker<Object>(context) {

            @Override
            public void weaveOnBefore(MonitorInfo<Object> monitorInfo) {
                nodeState.setBegin(begin);
                monitorInfo.addDigest("preBegin", begin);
                monitorInfo.addDigest("node", id);
                monitorInfo.addDigest("sync", node.isSync());
                monitorInfo.addDigest("ignore", true);
                nodeState.setIgnore(true);
            }

            @Override
            public Object internalCall() {
                return result;
            }

            @Override
            public void weaveOnAfter(MonitorInfo<Object> monitorInfo) {
                if (context.isDone()) {
                    LinkLogUtil.newTagLog(TAG_DAGRE_ALREADY_DONE)
                            .v1(name)
                            .v2("nodeDone_" + id)
                            .log();
                    return;
                }
                Object result = monitorInfo.getResult();
                nodeState.setEnd(context.calRunTime());
                nodeState.setResult(result);
                nodeState.setError(null);
                nodeState.setSlow(false);
                if (monitorInfo.isDebug() && result != null) {
                    try {
                        //json序列化结果快照
                        String resultSnapshot = JSON.toJSONString(result);
                        nodeState.setResultSnapshot(resultSnapshot);
                        monitorInfo.addDetail(MonitorInfo.RESULT, resultSnapshot);
                    } catch (Throwable e) {
                        LinkLogUtil.newTagLog(TAG_NODE_RESULT_SNAPSHOT_ERROR)
                                .v1(name)
                                .v2(id)
                                .addAttachment(MonitorInfo.ERROR, e)
                                .log();
                    }
                }

            }
        });

        //通知后续
        reportNodeDone(context, nodeWrapper, result);
    }

    /**
     * 同步执行节点
     *
     * @param begin
     * @param context
     * @param node
     */
    protected Object syncExecuteNode(int begin, DagreContext<T> context, DagreNode<T> node) {
        String id = node.getId();
        NodeState nodeState = context.getNodeState(id);
        return InvokeTemplate.monitor("Dagre", name, "execute_" + id, new MonitorInvoker<Object>(context) {

            @Override
            public void weaveOnBefore(MonitorInfo<Object> monitorInfo) {
                nodeState.setBegin(begin);
                monitorInfo.addDigest("preBegin", begin);
                monitorInfo.addDigest("node", id);
                monitorInfo.addDigest("sync", node.isSync());
                monitorInfo.addDigest("ignore", false);
                nodeState.setIgnore(false);
                //慢调用,如果动态配置就不需要从node获取了
                if (monitorInfo.getSlowTime() == null) {
                    monitorInfo.setSlowTime(node.getSlowTime(context));
                }
            }

            @Override
            public Object internalCall() throws Throwable {
                return node.execute(context);
            }

            @Override
            public void weaveOnAfter(MonitorInfo<Object> monitorInfo) {
                if (context.isDone()) {
                    LinkLogUtil.newTagLog(TAG_DAGRE_ALREADY_DONE)
                            .v1(name)
                            .v2("nodeDone_" + id)
                            .log();
                    return;
                }
                Object result = monitorInfo.getResult();
                nodeState.setEnd(context.calRunTime());
                nodeState.setResult(result);
                nodeState.setError(monitorInfo.getError());
                nodeState.setSlow(monitorInfo.getSlowTime() != null && monitorInfo.getCost() > monitorInfo.getSlowTime());
                if (monitorInfo.isDebug() && result != null) {
                    try {
                        //json序列化结果快照
                        String resultSnapshot = JSON.toJSONString(result);
                        nodeState.setResultSnapshot(resultSnapshot);
                        monitorInfo.addDetail(MonitorInfo.RESULT, resultSnapshot);
                    } catch (Throwable e) {
                        LinkLogUtil.newTagLog(TAG_NODE_RESULT_SNAPSHOT_ERROR)
                                .v1(name)
                                .v2(id)
                                .addAttachment(MonitorInfo.ERROR, e)
                                .log();
                    }
                }

            }
        });
    }

    /**
     * 每次当执行执行完毕触发下级
     *
     * @param context
     * @param doneNodeWrapper
     * @param nodeResult
     */
    private void reportNodeDone(DagreContext<T> context, NodeWrapper<T> doneNodeWrapper, Object nodeResult) throws Throwable {
        if (context.isDone()) {
            LinkLogUtil.newTagLog(TAG_DAGRE_ALREADY_DONE)
                    .v1(name)
                    .v2("reportNodeDone_" + doneNodeWrapper.fetchNodeId())
                    .log();
            return;
        }
        String id = doneNodeWrapper.fetchNodeId();
        if (nodeResult instanceof DagreResult) {
            ((DagreResult) nodeResult).setStatus(DagreResult.StatusEnum.NODE_RETURN);
            //中间结束
            context.markDagreDone(id, (DagreResult) nodeResult);
            return;
        }

        //1检查该节点执行完毕后是否全部完成
        //所有节点执行完代表结束了
        if (context.markNodeDone(id)) {
            DagreResult result = DagreResult.buildSuccess(null);
            result.setStatus(DagreResult.StatusEnum.ALL_OVER);
            context.markDagreDone(id, result);
            return;
        }

        //2寻找需要触发的节点
        Collection<DagreEngine.NodeWrapper<T>> fires = context.tryFires(doneNodeWrapper);
        if (fires == null || fires.isEmpty()) {
            return;
        }
        LinkLogUtil.newTagLog(TAG_FIRE_DAGRE_NODE)
                .v1(name)
                .v2(id + "->" + CommonUtil.join(fires, ","))
                .log();
        fireNodes(context, fires);
    }




    /*-------------------------分割线-------------------------*/


    /**
     * 节点库
     */
    private final Map<String, NodeWrapper<T>> nodeLibrary = new HashMap<>();


    /**
     * 是否冻结
     * 初始化后对节点进行冻结
     * 后续的每次注册都会进行特殊操作验证合理性
     * freeze 自动处理
     *
     * @see DagreEngine#tryFreeze
     */
    private volatile boolean freeze = false;

    /**
     * 根节点列表
     * 不可变集合
     * freeze 时自行设置
     *
     * @see DagreEngine#tryFreeze
     */
    private Set<NodeWrapper<T>> roots;

    /**
     * 节点id列表
     * 不可变集合
     * 每次更新节点时 自行设置
     *
     * @see DagreEngine#tryFreeze
     */
    private Set<String> allIds;


    /**
     * 获取根节点
     *
     * @return
     */
    private Set<NodeWrapper<T>> getRoots() {
        return roots;
    }

    /**
     * 根据id获取节点包装
     *
     * @param id
     * @return
     */
    private NodeWrapper<T> getNodeWrapper(String id) {
        return id == null ? null : nodeLibrary.get(id);
    }


    /**
     * 节点注册完成后
     * 1.节点依赖真实性验证&节点循环依赖验证
     * 2.初始化roots,allIds及初始化node的dependMe属性
     * 3.freeze=true
     */
    private synchronized void freeze() {
        checkDependReachableAndLink(nodeLibrary);
        refreshIds();
        freeze = true;
    }


//    /**
//     * 冻结状态添加
//     * 1.验证依赖可达性&验证节点循环依赖
//     * 3.初始化根节点&dependMe
//     *
//     * @param node
//     */
//    private void freezeRegister(DagreNode<T> node) throws SimpleException {
//        //预添加校验
//        Map<String, NodeWrapper<T>> preMap = new HashMap<>(nodeLibrary);
//        NodeWrapper<T> nodeWrapper = new NodeWrapper<>(node);
//        preMap.put(nodeWrapper.fetchNodeId(), nodeWrapper);
//        checkDependReachableAndLink(preMap);
//
//        nodeLibrary.put(nodeWrapper.fetchNodeId(), nodeWrapper);
//        refreshIds();
//    }
//
//
//    /**
//     * 冻结状态下解除注册
//     *
//     * @param nodeWrapper
//     */
//    private void freezeUnRegister(NodeWrapper<T> nodeWrapper) {
//        Set<String> dependMe = nodeWrapper.getDependMes();
//        String id = nodeWrapper.fetchNodeId();
//
//        if (!dependMe.isEmpty()) {
//            throw new SimpleException(SimpleException.CONFIG_INVALID, "can not unRegister {1}, current node is depend by :{0}", dependMe, id);
//        }
//        //删除
//        nodeLibrary.remove(id);
//        //更新他依赖的
//        refreshIds();
//    }


    /**
     * 依赖可达性分析&成环验证
     *
     * @param nodeMap
     */
    private void checkDependReachableAndLink(Map<String, NodeWrapper<T>> nodeMap) {
        //依赖可达性分析
        for (Map.Entry<String, NodeWrapper<T>> entry : nodeMap.entrySet()) {
            NodeWrapper<T> nodeWrapper = entry.getValue();
            checkOneNodeDependReachable(nodeMap, nodeWrapper);
        }

        //是否成环验证
        for (Map.Entry<String, NodeWrapper<T>> entry : nodeMap.entrySet()) {
            NodeWrapper<T> nodeWrapper = entry.getValue();
            links(nodeMap, nodeWrapper);
        }
    }

    /**
     * 验证某节点依赖的节点是否均存在于该map
     *
     * @param nodeMap
     * @param nodeWrapper
     */
    private void checkOneNodeDependReachable(Map<String, NodeWrapper<T>> nodeMap, NodeWrapper<T> nodeWrapper) {
        Set<String> meDepend = nodeWrapper.getMeDepends();
        if (CommonUtil.isEmpty(meDepend)) {
            return;
        }
        for (String depend : meDepend) {
            NodeWrapper<T> dependNodeWrapper = nodeMap.get(depend);
            if (dependNodeWrapper == null) {
                throw new SimpleException(SimpleException.CONFIG_INVALID, "id depend not reachable id:{0}, dependId:{1}", nodeWrapper.fetchNodeId(), depend);
            }
        }
    }

    private void refreshIds() {
        //不可变ids
        roots = Collections.unmodifiableSet(nodeLibrary.entrySet().stream().filter(entry -> CommonUtil.isEmpty(entry.getValue().getMeDepends())).map(Map.Entry::getValue).collect(Collectors.toSet()));
        allIds = Collections.unmodifiableSet(nodeLibrary.keySet());

        //计算dependMes
        //清除原有数据
        nodeLibrary.forEach((id, wrapper) -> wrapper.setDependMes(null));
        for (Map.Entry<String, NodeWrapper<T>> entry : nodeLibrary.entrySet()) {
            NodeWrapper<T> nodeWrapper = entry.getValue();
            String id = nodeWrapper.fetchNodeId();
            Set<String> meDepend = nodeWrapper.getMeDepends();
            if (meDepend != null) {
                for (String depend : meDepend) {
                    NodeWrapper<T> dependNodeWrapper = nodeLibrary.get(depend);
                    Set<String> dependMes = dependNodeWrapper.getDependMes();
                    if (dependMes == null) {
                        dependMes = new HashSet<>();
                        dependNodeWrapper.setDependMes(dependMes);
                    }
                    dependMes.add(id);
                }
            }
        }
        //不可变化
        nodeLibrary.forEach((id, wrapper) -> wrapper.setDependMes(Collections.unmodifiableSet(wrapper.getDependMes() == null ? new HashSet<>() : wrapper.getDependMes())));
    }


    private List<String> links(Map<String, NodeWrapper<T>> nodeMap, NodeWrapper<T> nodeWrapper) {
        List<String> link = new LinkedList<>();
        link.add(nodeWrapper.fetchNodeId());
        return deepLink(nodeMap, nodeWrapper, link);
    }

    private List<String> deepLink(Map<String, NodeWrapper<T>> nodeMap, NodeWrapper<T> nodeWrapper, List<String> link) {
        List<String> endLink = new ArrayList<>();
        Set<String> meDepend = nodeWrapper.getMeDepends();
        if (CommonUtil.isEmpty(meDepend)) {
            endLink.add(CommonUtil.join(link, ">"));
            return endLink;
        }
        for (String depend : meDepend) {
            if (link.contains(depend)) {
                throw new SimpleException(SimpleException.CONFIG_INVALID, "node:" + nodeWrapper.fetchNodeId() + ", currentDepend:" + depend + ", current link:" + CommonUtil.join(link, ">") + ", is a circle ,please check ");
            }
            List<String> nextLink = new ArrayList<>(link);
            nextLink.add(depend);
            endLink.addAll(deepLink(nodeMap, nodeMap.get(depend), nextLink));
        }
        return endLink;
    }


    /**
     * 节点包装
     *
     * @Author shaopeng
     */
    public static class NodeWrapper<T> {

        /**
         * 节点实现
         */
        private DagreNode<T> node;

        /**
         * 依赖的节点
         * NodeLibrary 初始化时自行设置,用户无需处理
         * 不可变
         */
        private final Set<String> meDepends;

        /**
         * 被依赖的节点
         * NodeLibrary 初始化时自行设置,用户无需处理
         * 冻结后不可变
         */
        private Set<String> dependMes;

        private NodeWrapper(DagreNode<T> node) {
            if (node == null) {
                throw new IllegalArgumentException("node can not be null");
            }
            this.node = node;
            Collection<String> dependIds = node.getDependIds();
            if (dependIds != null) {
                //清除null
                dependIds.remove(null);
            }
            this.meDepends = Collections.unmodifiableSet(new HashSet<>(dependIds == null ? new ArrayList<>() : dependIds));
        }


        public String fetchNodeId() {
            return node.getId();
        }


        /**
         * 我依赖谁
         *
         * @return
         */
        public Set<String> getMeDepends() {
            return meDepends;
        }

        /**
         * 获取谁依赖我
         *
         * @return
         */
        public Set<String> getDependMes() {
            return dependMes;
        }


        public DagreNode<T> getNode() {
            return node;
        }

        private void setNode(DagreNode<T> node) {
            this.node = node;
        }

        private void setDependMes(Set<String> dependMes) {
            this.dependMes = dependMes;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            return Objects.equals(fetchNodeId(), ((NodeWrapper<T>) o).fetchNodeId());
        }

        @Override
        public int hashCode() {
            return Objects.hash(fetchNodeId());
        }

        @Override
        public String toString() {
            return fetchNodeId();
        }
    }
}
